﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using IPC.Communication.Framework.Core;
using IPC.Communication.Framework.Core.Address;
using IPC.Communication.Framework.Core.IMessage;
using IPC.Communication.Framework.Core.Net;
using IPC.Communication.Framework.Profinet.Melsec.Helper;
using IPC.Communication.Framework.Reflection;

namespace IPC.Communication.Framework.Profinet.Melsec
{
    public class MelsecMcRNet : NetworkDeviceBase, IReadWriteMc, IReadWriteDevice, IReadWriteNet
    {
        private McType _mcType = McType.McBinary;
        private byte _networkNumber = 0;
        private byte _networkStationNumber = 0;

        public McType McType
        {
            get { return _mcType; }
            set { _mcType = value; }
        }

        public byte NetworkNumber
        {
            get { return _networkNumber; }
            set { _networkNumber = value; }
        }


        public byte NetworkStationNumber
        {
            get { return _networkStationNumber; }
            set { _networkStationNumber = value; }
        }


        public MelsecMcRNet()
        {
            base.WordLength = 1;
            base.ByteTransform = new RegularByteTransform();
        }

        public MelsecMcRNet(string ipAddress, int port)
        {
            base.WordLength = 1;
            IpAddress = ipAddress;
            Port = port;
            base.ByteTransform = new RegularByteTransform();
        }

        protected override INetMessage GetNewNetMessage()
        {
            return new MelsecQnA3EBinaryMessage();
        }

        public virtual OperateResult<McAddressData> McAnalysisAddress(string address, ushort length)
        {
            return McAddressData.ParseMelsecRFrom(address, length);
        }

        protected override byte[] PackCommandWithHeader(byte[] command)
        {
            return McBinaryHelper.PackMcCommand(command, NetworkNumber, NetworkStationNumber);
        }

        protected override OperateResult<byte[]> UnpackResponseContent(byte[] send, byte[] response)
        {
            OperateResult operateResult = McBinaryHelper.CheckResponseContentHelper(response);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            return OperateResult.CreateSuccessResult(response.RemoveBegin(11));
        }

        public byte[] ExtractActualData(byte[] response, bool isBit)
        {
            return McBinaryHelper.ExtractActualDataHelper(response, isBit);
        }

        [HslMqttApi("ReadByteArray", "")]
        public override OperateResult<byte[]> Read(string address, ushort length)
        {
            return McHelper.Read(this, address, length);
        }

        [HslMqttApi("WriteByteArray", "")]
        public override OperateResult Write(string address, byte[] value)
        {
            return McHelper.Write(this, address, value);
        }

        //[AsyncStateMachine(typeof(<ReadAsync>d__19))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult<byte[]>> ReadAsync(string address, ushort length)
        //{
        //    <ReadAsync>d__19 stateMachine = new <ReadAsync>d__19();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__20))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult> WriteAsync(string address, byte[] value)
        //{
        //    <WriteAsync>d__20 stateMachine = new <WriteAsync>d__20();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        [HslMqttApi("随机读取PLC的数据信息，可以跨地址，跨类型组合，但是每个地址只能读取一个word，也就是2个字节的内容。收到结果后，需要自行解析数据")]
        public OperateResult<byte[]> ReadRandom(string[] address)
        {
            return McHelper.ReadRandom(this, address);
        }

        [HslMqttApi(ApiTopic = "ReadRandoms", Description = "随机读取PLC的数据信息，可以跨地址，跨类型组合，每个地址是任意的长度。收到结果后，需要自行解析数据，目前只支持字地址，比如D区，W区，R区，不支持X，Y，M，B，L等等")]
        public OperateResult<byte[]> ReadRandom(string[] address, ushort[] length)
        {
            return McHelper.ReadRandom(this, address, length);
        }

        public OperateResult<short[]> ReadRandomInt16(string[] address)
        {
            return McHelper.ReadRandomInt16(this, address);
        }

        public OperateResult<ushort[]> ReadRandomUInt16(string[] address)
        {
            return McHelper.ReadRandomUInt16(this, address);
        }

        //[AsyncStateMachine(typeof(<ReadRandomAsync>d__25))]
        //[DebuggerStepThrough]
        //public Task<OperateResult<byte[]>> ReadRandomAsync(string[] address)
        //{
        //    <ReadRandomAsync>d__25 stateMachine = new <ReadRandomAsync>d__25();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<ReadRandomAsync>d__26))]
        //[DebuggerStepThrough]
        //public Task<OperateResult<byte[]>> ReadRandomAsync(string[] address, ushort[] length)
        //{
        //    <ReadRandomAsync>d__26 stateMachine = new <ReadRandomAsync>d__26();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<ReadRandomInt16Async>d__27))]
        //[DebuggerStepThrough]
        //public Task<OperateResult<short[]>> ReadRandomInt16Async(string[] address)
        //{
        //    <ReadRandomInt16Async>d__27 stateMachine = new <ReadRandomInt16Async>d__27();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<short[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<ReadRandomUInt16Async>d__28))]
        //[DebuggerStepThrough]
        //public Task<OperateResult<ushort[]>> ReadRandomUInt16Async(string[] address)
        //{
        //    <ReadRandomUInt16Async>d__28 stateMachine = new <ReadRandomUInt16Async>d__28();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<ushort[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        [HslMqttApi("ReadBoolArray", "")]
        public override OperateResult<bool[]> ReadBool(string address, ushort length)
        {
            return McHelper.ReadBool(this, address, length);
        }

        [HslMqttApi("WriteBoolArray", "")]
        public override OperateResult Write(string address, bool[] values)
        {
            return McHelper.Write(this, address, values);
        }

        //[AsyncStateMachine(typeof(<ReadBoolAsync>d__31))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult<bool[]>> ReadBoolAsync(string address, ushort length)
        //{
        //    <ReadBoolAsync>d__31 stateMachine = new <ReadBoolAsync>d__31();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<bool[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__32))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult> WriteAsync(string address, bool[] values)
        //{
        //    <WriteAsync>d__32 stateMachine = new <WriteAsync>d__32();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.values = values;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public override string ToString()
        {
            return String.Format("MelsecMcRNet[{0}:{1}]", IpAddress, Port);
        }

        public static OperateResult<MelsecMcDataType, int> AnalysisAddress(string address)
        {
            try
            {
                if (address.StartsWith("LSTS"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_LSTS, Convert.ToInt32(address.Substring(4), MelsecMcDataType.R_LSTS.FromBase));
                }
                if (address.StartsWith("LSTC"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_LSTC, Convert.ToInt32(address.Substring(4), MelsecMcDataType.R_LSTC.FromBase));
                }
                if (address.StartsWith("LSTN"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_LSTN, Convert.ToInt32(address.Substring(4), MelsecMcDataType.R_LSTN.FromBase));
                }
                if (address.StartsWith("STS"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_STS, Convert.ToInt32(address.Substring(3), MelsecMcDataType.R_STS.FromBase));
                }
                if (address.StartsWith("STC"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_STC, Convert.ToInt32(address.Substring(3), MelsecMcDataType.R_STC.FromBase));
                }
                if (address.StartsWith("STN"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_STN, Convert.ToInt32(address.Substring(3), MelsecMcDataType.R_STN.FromBase));
                }
                if (address.StartsWith("LTS"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_LTS, Convert.ToInt32(address.Substring(3), MelsecMcDataType.R_LTS.FromBase));
                }
                if (address.StartsWith("LTC"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_LTC, Convert.ToInt32(address.Substring(3), MelsecMcDataType.R_LTC.FromBase));
                }
                if (address.StartsWith("LTN"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_LTN, Convert.ToInt32(address.Substring(3), MelsecMcDataType.R_LTN.FromBase));
                }
                if (address.StartsWith("LCS"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_LCS, Convert.ToInt32(address.Substring(3), MelsecMcDataType.R_LCS.FromBase));
                }
                if (address.StartsWith("LCC"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_LCC, Convert.ToInt32(address.Substring(3), MelsecMcDataType.R_LCC.FromBase));
                }
                if (address.StartsWith("LCN"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_LCN, Convert.ToInt32(address.Substring(3), MelsecMcDataType.R_LCN.FromBase));
                }
                if (address.StartsWith("TS"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_TS, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_TS.FromBase));
                }
                if (address.StartsWith("TC"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_TC, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_TC.FromBase));
                }
                if (address.StartsWith("TN"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_TN, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_TN.FromBase));
                }
                if (address.StartsWith("CS"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_CS, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_CS.FromBase));
                }
                if (address.StartsWith("CC"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_CC, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_CC.FromBase));
                }
                if (address.StartsWith("CN"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_CN, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_CN.FromBase));
                }
                if (address.StartsWith("SM"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_SM, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_SM.FromBase));
                }
                if (address.StartsWith("SB"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_SB, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_SB.FromBase));
                }
                if (address.StartsWith("DX"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_DX, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_DX.FromBase));
                }
                if (address.StartsWith("DY"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_DY, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_DY.FromBase));
                }
                if (address.StartsWith("SD"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_SD, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_SD.FromBase));
                }
                if (address.StartsWith("SW"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_SW, Convert.ToInt32(address.Substring(2), MelsecMcDataType.R_SW.FromBase));
                }
                if (address.StartsWith("X"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_X, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_X.FromBase));
                }
                if (address.StartsWith("Y"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_Y, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_Y.FromBase));
                }
                if (address.StartsWith("M"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_M, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_M.FromBase));
                }
                if (address.StartsWith("L"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_L, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_L.FromBase));
                }
                if (address.StartsWith("F"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_F, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_F.FromBase));
                }
                if (address.StartsWith("V"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_V, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_V.FromBase));
                }
                if (address.StartsWith("S"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_S, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_S.FromBase));
                }
                if (address.StartsWith("B"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_B, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_B.FromBase));
                }
                if (address.StartsWith("D"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_D, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_D.FromBase));
                }
                if (address.StartsWith("W"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_W, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_W.FromBase));
                }
                if (address.StartsWith("R"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_R, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_R.FromBase));
                }
                if (address.StartsWith("Z"))
                {
                    return OperateResult.CreateSuccessResult(MelsecMcDataType.R_Z, Convert.ToInt32(address.Substring(1), MelsecMcDataType.R_Z.FromBase));
                }
                return new OperateResult<MelsecMcDataType, int>(StringResources.Language.NotSupportedDataType);
            }
            catch (Exception ex)
            {
                return new OperateResult<MelsecMcDataType, int>(ex.Message);
            }
        }

        public static byte[] BuildReadMcCoreCommand(McAddressData address, bool isBit)
        {
            return new byte[12]
		{
			1,
			4,
			(byte)(isBit ? 1 : 0),
			0,
			BitConverter.GetBytes(address.AddressStart)[0],
			BitConverter.GetBytes(address.AddressStart)[1],
			BitConverter.GetBytes(address.AddressStart)[2],
			BitConverter.GetBytes(address.AddressStart)[3],
			BitConverter.GetBytes(address.McDataType.DataCode)[0],
			BitConverter.GetBytes(address.McDataType.DataCode)[1],
			(byte)((int)address.Length % 256),
			(byte)((int)address.Length / 256)
		};
        }

        public static byte[] BuildWriteWordCoreCommand(McAddressData address, byte[] value)
        {
            if (value == null)
            {
                value = new byte[0];
            }
            byte[] array = new byte[12 + value.Length];
            array[0] = 1;
            array[1] = 20;
            array[2] = 0;
            array[3] = 0;
            array[4] = BitConverter.GetBytes(address.AddressStart)[0];
            array[5] = BitConverter.GetBytes(address.AddressStart)[1];
            array[6] = BitConverter.GetBytes(address.AddressStart)[2];
            array[7] = BitConverter.GetBytes(address.AddressStart)[3];
            array[8] = BitConverter.GetBytes(address.McDataType.DataCode)[0];
            array[9] = BitConverter.GetBytes(address.McDataType.DataCode)[1];
            array[10] = (byte)(value.Length / 2 % 256);
            array[11] = (byte)(value.Length / 2 / 256);
            value.CopyTo(array, 12);
            return array;
        }

        public static byte[] BuildWriteBitCoreCommand(McAddressData address, bool[] value)
        {
            if (value == null)
            {
                value = new bool[0];
            }
            byte[] array = MelsecHelper.TransBoolArrayToByteData(value);
            byte[] array2 = new byte[12 + array.Length];
            array2[0] = 1;
            array2[1] = 20;
            array2[2] = 1;
            array2[3] = 0;
            array2[4] = BitConverter.GetBytes(address.AddressStart)[0];
            array2[5] = BitConverter.GetBytes(address.AddressStart)[1];
            array2[6] = BitConverter.GetBytes(address.AddressStart)[2];
            array2[7] = BitConverter.GetBytes(address.AddressStart)[3];
            array2[8] = BitConverter.GetBytes(address.McDataType.DataCode)[0];
            array2[9] = BitConverter.GetBytes(address.McDataType.DataCode)[1];
            array2[10] = (byte)(value.Length % 256);
            array2[11] = (byte)(value.Length / 256);
            array.CopyTo(array2, 12);
            return array2;
        }
    }
}
